package service;


import domain.cms.AbstractPage;
import domain.cms.CmsPage;
import domain.shop.Product;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.jpa.Search;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;

@Transactional(propagation = Propagation.REQUIRED)
@Service
public class SearcherImpl implements Searcher {

    @PersistenceContext
    private EntityManager em;

    @SuppressWarnings("unchecked")
    @Transactional(readOnly = true)
    public List<? extends AbstractPage> search(final String fulltextQuery) {
        Assert.notNull(fulltextQuery, "retezec pro vyhledavani nesmi byt null!");

        //vezmeme instanci manazeru fulltextu
        FullTextEntityManager ftEm = Search.getFullTextEntityManager(em);


        //vytvorime parser pro prohledavane atributy firmy, pouzijeme standardni analyzer
        QueryParser parser = new MultiFieldQueryParser(
                new String[]{"login", "attribute.title", "attribute.content"},
                new StandardAnalyzer());

        //vytvorime dotaz do Lucene
        org.apache.lucene.search.Query luceneQuery;

        //pokud po zruseni vsech bilych znaku a hvezdicek zustane jen prazdny retezec, pak vracime vsechny zaznamy
        //napr. dotaz "**** * **  *" bude vyhodnocen tak, ze chceme prohledavat vsechny firmy
        if (StringUtils.trimAllWhitespace(StringUtils.deleteAny(fulltextQuery, "*")).isEmpty()) {
            luceneQuery = new MatchAllDocsQuery();
        } else { //byl zadan retezec, vyhledavame
            try {
                luceneQuery = parser.parse(fulltextQuery); //zparsujeme predany dotaz pomoci parseru Lucene
            } catch (ParseException e) { //neplatny dotaz, prekonverujeme na runtime vyjimku, nemusime zachytavat
                throw new RuntimeException("Neplatny dotaz do fulltextu: " + fulltextQuery, e);
            }
        }
//            luceneQuery = new MatchAllDocsQuery();

        //vytvorime normalni JPA dotaz, ale pres rozhrani fulltextu
        FullTextQuery query = ftEm.createFullTextQuery(
                luceneQuery,
                CmsPage.class);
        //tridime dle relevance DESC, pote dle id DESC
        SortField[] sortFields = new SortField[2]; //BACHA pole nesmi bejt vetsi nez je potreba
        sortFields[0] = SortField.FIELD_SCORE; //relevance, default DESC
        sortFields[1] = new SortField("id", SortField.LONG, true); //id, je to long, DESC=true
        Sort sort = new Sort(sortFields);

        //pridame trideni do dotazu
        query.setSort(sort);

        //a vratime rovnou vyhovujici seznam firem z ORM
        query.setMaxResults(50);
        List list = query.getResultList();
//        Integer size = query.getResultSize();
//        System.err.println(size);
//        for (Object cmsPage : list) {
//            System.err.println(cmsPage.toString());
//        }
        return list;


    }

    public List<Product> searchProducts(String fulltextQuery) {
        Assert.notNull(fulltextQuery, "retezec pro vyhledavani nesmi byt null!");

        //vezmeme instanci manazeru fulltextu
        FullTextEntityManager ftEm = Search.getFullTextEntityManager(em);


        //vytvorime parser pro prohledavane atributy firmy, pouzijeme standardni analyzer
        QueryParser parser = new MultiFieldQueryParser(
                new String[]{"name", "cmsAttribute.title", "cmsAttribute.content",
                        "cmsAttribute.shortContent"}, new StandardAnalyzer());

        //vytvorime dotaz do Lucene
        org.apache.lucene.search.Query luceneQuery;

        //pokud po zruseni vsech bilych znaku a hvezdicek zustane jen prazdny retezec, pak vracime vsechny zaznamy
        //napr. dotaz "**** * **  *" bude vyhodnocen tak, ze chceme prohledavat vsechny firmy
        if (StringUtils.trimAllWhitespace(StringUtils.deleteAny(fulltextQuery, "*")).isEmpty()) {
            luceneQuery = new MatchAllDocsQuery();
        } else { //byl zadan retezec, vyhledavame
            try {
                luceneQuery = parser.parse(fulltextQuery); //zparsujeme predany dotaz pomoci parseru Lucene
            } catch (ParseException e) { //neplatny dotaz, prekonverujeme na runtime vyjimku, nemusime zachytavat
                throw new RuntimeException("Neplatny dotaz do fulltextu: " + fulltextQuery, e);
            }
        }
//            luceneQuery = new MatchAllDocsQuery();

        //vytvorime normalni JPA dotaz, ale pres rozhrani fulltextu
        FullTextQuery query = ftEm.createFullTextQuery(luceneQuery, Product.class);
        //tridime dle relevance DESC, pote dle id DESC
        SortField[] sortFields = new SortField[2]; //BACHA pole nesmi bejt vetsi nez je potreba
        sortFields[0] = SortField.FIELD_SCORE; //relevance, default DESC
        sortFields[1] = new SortField("id", SortField.LONG, true); //id, je to long, DESC=true
        Sort sort = new Sort(sortFields);

        //pridame trideni do dotazu
        query.setSort(sort);

        //a vratime rovnou vyhovujici seznam firem z ORM
        query.setMaxResults(50);
        List list = query.getResultList();
//        Integer size = query.getResultSize();
//        System.err.println(size);
//        for (Object cmsPage : list) {
//            System.err.println(cmsPage.toString());
//        }
        return list;
    }
}
